<?php

class Form_Exception extends CMS_Exception {}
class Form_Incomplete_Exception extends Form_Exception {}
class Form_Field_Exception extends Form_Exception {}
class Form_Field_Not_Found_Exception extends Form_Field_Exception {}
class Form_Field_Invalid_Exception extends Form_Field_Exception {}

class Form {

	protected $id;
	protected $fields;

	protected $submitted;
	protected $complete;

	public function __construct($id, $action){
		$this->action = $action;
		$this->id = $id;
		$this->fields = array();
	}

	public function add($field){
		if(!($field instanceof Form_Field)){
			throw new Form_Field_Invalid_Exception();
		}
		$this->fields[$field->name()] = $field;
	}

	public function run(){
		$this->submitted = false;
		$this->complete = false;

		$get =& $_POST;
		foreach($this->id as $value){
			if(!isset($get[$value])){
				return;
			}
			$get =& $get[$value];
		}

		$this->submitted = true;

		try {
			foreach($this->fields as $name => $field){
				$field->run(isset($get[$name]) ? $get[$name] : null);
			}
		} catch (Exception $e){
			return;
		}

		$this->complete = true;

		return;
	}

	public function data(){
		if(!$this->complete){
			throw new Form_Incomplete_Exception();
		}
		$data = array();
		foreach($this->fields as $name => $field){
			$data[$name] = $field->data();
		}
		return $data;
	}

	public function output(){
		$tpl = Output::getInstance()->Template(array('form'));
		$tpl->action = $this->action;
		foreach($this->fields as $field){
			$tpl->fields[] = $field->output($this->id);
		}
		return $tpl;
	}

}

abstract class Form_Field {

	protected static $types;

	protected $validators = array();
	protected $name;
	protected $title;
	
	public static function Register($name, $class, $file){
		if(!isset(Form_Field::$types[$name][$class])){
			Form_Field::$types[$name][$class] = array(
				'class' => $class,
				'file' => $file
			);
		}
	}
	
	public function __construct($name){
		$this->name = $name;
	}

	public function title($title){
		$this->title = $title;
	}

	public function name(){
		return $this->name;
	}

	abstract public function data();

	abstract public function run($value);

	public function validate($validator){
		$this->validators[] = $validator;
	}

	public function output($base, $main = null){
		$tpl = Output::getInstance()->Template(array('form','field'));
		if(isset($main)){ $tpl->main = $main; } 
		return $tpl;
	}

	public static function Create($name, $types){
		if(!is_array($types)){
			$types = array($types);
		}

		foreach($types as $lookup){
			if(isset(Form_Field::$types[$lookup])){
				foreach(Form_Field::$types[$lookup] as $k => $data){
					try {
						CMS::File($data['file']);
						$class = $data['class'];
						if(!is_subclass_of($class, 'Form_Field')){
							throw new Form_Field_Invalid_Exception($name, $type);
						}
						return new $class($name);
					} catch (Exception $e) {
					}
				}
			}
		}
		throw new Form_Field_Not_Found_Exception($name, $types);
	}

}

Form_Field::Register('text','Form_Field_Textbox','form/field/textbox');
Form_Field::Register('textarea','Form_Field_Textarea','form/field/textarea');
Form_Field::Register('select','Form_Field_Select','form/field/select');
Form_Field::Register('timedate','Form_Field_Date','form/field/date');
Form_Field::Register('submit','Form_Field_Submit','form/field/submit');
Form_Field::Register('checkbox','Form_Field_Checkbox','form/field/checkbox');
Form_Field::Register('password','Form_Field_Password','form/field/password');

